1 Detalles de la actividad

1.1 Descripción

Rellenar

1.2 Objetivos

Rellenar

1.3 Competencias

Rellenar

2 Introducción

2.1 Elección del DataSet


El conjunto de datos que hemos elegido está en la siguiente url: https://www.kaggle.com/fedesoriano/heart-failure-prediction. Se ha escogido ya que es una temática muy interesante las enfermedades cardiovasculares y al mismo tiempo comprobamos que haya campos numéricos y categóricos. Lo que pretende responder es como afecta o no las enfermedades cardiovasculares en función de las caracterísitcas de las personas.


2.2 Carga del dataset


Se lee el fichero “heart.csv”.

heart <- read.csv("heart.csv",sep=",")

2.3 Explicación de las variables

A continuación, obtenemos el listado de variables:

str(heart)
## 'data.frame':    918 obs. of  12 variables:
##  $ Age           : int  40 49 37 48 54 39 45 54 37 48 ...
##  $ Sex           : chr  "M" "F" "M" "F" ...
##  $ ChestPainType : chr  "ATA" "NAP" "ATA" "ASY" ...
##  $ RestingBP     : int  140 160 130 138 150 120 130 110 140 120 ...
##  $ Cholesterol   : int  289 180 283 214 195 339 237 208 207 284 ...
##  $ FastingBS     : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ RestingECG    : chr  "Normal" "Normal" "ST" "Normal" ...
##  $ MaxHR         : int  172 156 98 108 122 170 170 142 130 120 ...
##  $ ExerciseAngina: chr  "N" "N" "N" "Y" ...
##  $ Oldpeak       : num  0 1 0 1.5 0 0 0 0 1.5 0 ...
##  $ ST_Slope      : chr  "Up" "Flat" "Up" "Flat" ...
##  $ HeartDisease  : int  0 1 0 1 0 0 0 0 1 0 ...
  • Age : edad del paciente.
  • Sex : sexo del paciente.
  • ChestPainType : Tipo de dolor del pecho.
  • RestingBP : presión arterial en reposo (sistólica).
  • Cholesterol : colesterol sérico.
  • FastingBS : azúcar en sangre en ayunas.
  • RestingECG: resultados del electrocardiograma en reposo.
  • MaxHR: frecuencia cardíaca máxima alcanzada.
  • ExerciseAngina: angina inducida por el ejercicio.
  • Oldpeak : ejercicio inducido por la depresión (ST) en relación con el descanso.
  • ST_Slope : pendiente del segmento ST del ejercicio pico.
  • HeartDisease : clase de salida.

  • Se muestra un resumen de las variables.

    summary(heart)
    ##       Age            Sex            ChestPainType        RestingBP    
    ##  Min.   :28.00   Length:918         Length:918         Min.   :  0.0  
    ##  1st Qu.:47.00   Class :character   Class :character   1st Qu.:120.0  
    ##  Median :54.00   Mode  :character   Mode  :character   Median :130.0  
    ##  Mean   :53.51                                         Mean   :132.4  
    ##  3rd Qu.:60.00                                         3rd Qu.:140.0  
    ##  Max.   :77.00                                         Max.   :200.0  
    ##   Cholesterol      FastingBS       RestingECG            MaxHR      
    ##  Min.   :  0.0   Min.   :0.0000   Length:918         Min.   : 60.0  
    ##  1st Qu.:173.2   1st Qu.:0.0000   Class :character   1st Qu.:120.0  
    ##  Median :223.0   Median :0.0000   Mode  :character   Median :138.0  
    ##  Mean   :198.8   Mean   :0.2331                      Mean   :136.8  
    ##  3rd Qu.:267.0   3rd Qu.:0.0000                      3rd Qu.:156.0  
    ##  Max.   :603.0   Max.   :1.0000                      Max.   :202.0  
    ##  ExerciseAngina        Oldpeak          ST_Slope          HeartDisease   
    ##  Length:918         Min.   :-2.6000   Length:918         Min.   :0.0000  
    ##  Class :character   1st Qu.: 0.0000   Class :character   1st Qu.:0.0000  
    ##  Mode  :character   Median : 0.6000   Mode  :character   Median :1.0000  
    ##                     Mean   : 0.8874                      Mean   :0.5534  
    ##                     3rd Qu.: 1.5000                      3rd Qu.:1.0000  
    ##                     Max.   : 6.2000                      Max.   :1.0000

    A partir de esto, se puede concluir con que hay 12 variables y 918 observaciones. También se aprecia que en el dataset hay 3 tipos de datos:

  • Variables numéricas: Oldpeak.
  • Variables de tipo carácter: Sex, ChestPainType, RestingECG, ExerciseAngina, ST_Slope.
  • Variables de tipo entero: Age, RestingBP, Cholesterol, FastingBS, MaxHR, HeartDisease.
  • 2.4 Importancia y objetivos de los análisis

    3 Preprocesado de datos

    3.1 Conversión y estandarización

    Pasamos los valores int a numeric y los char a factor.

    heart$Age <- as.numeric(heart$Age)
    heart$Sex <- as.factor(heart$Sex)
    heart$ChestPainType <- as.factor(heart$ChestPainType)
    heart$RestingBP <- as.numeric(heart$RestingBP)
    heart$Cholesterol <- as.numeric(heart$Cholesterol)
    heart$FastingBS <- as.numeric(heart$FastingBS)
    heart$RestingECG  <- as.factor(heart$RestingECG)
    heart$MaxHR <- as.numeric(heart$MaxHR)
    heart$ExerciseAngina <- as.factor(heart$ExerciseAngina)
    heart$ST_Slope <- as.factor(heart$ST_Slope)
    heart$HeartDisease <- as.numeric(heart$HeartDisease)

    3.2 Estudio de outliers

    En este apartado, se va a mostrar el diagrama de cajas de cada una de las variables numéricas para comprobar si hay posibles outliers.

    Age:

    Se aprecia que en la variable “Age” no hay ningún valor extremo.

    boxplot(heart$Age,main="Edad del paciente")

    boxplot.stats(heart$Age)$out
    ## numeric(0)

    RestingBP:

    En el campo “RestingBP” se observa algunos outliers, pero no se eliminarán debido a que la presión arterial sistólica puede tener valores superiores a 180 (esto sería una crisis de hipertensión).

    boxplot(heart$RestingBP,main="Presión arterial en reposo")

    boxplot.stats(heart$RestingBP)$out
    ##  [1] 190 180 180 180 200 180 180 180  80 200 185 200 180 180   0 178 172 180 190
    ## [20] 174 178 180 200 192 178 180 180 172

    Cholesterol:

    En esta variable se aprecian una serie de valores extremos, pero por el contrario no es extraño ya que un colesterol de 603 se puede tener (https://www.tuotromedico.com/parametros/colesterol-en-sangre-alto.htm), aunque es un valor muy elevado. También se puede tener el valor 100 que es óptimo.

    boxplot(heart$Cholesterol,main="Colesterol")

    boxplot.stats(heart$Cholesterol)$out
    ##   [1] 468 518 412 529 466 603 491   0   0   0   0   0   0   0   0   0   0   0
    ##  [19]   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
    ##  [37]   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
    ##  [55]   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
    ##  [73]   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
    ##  [91]   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
    ## [109]   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
    ## [127]   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
    ## [145]   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
    ## [163]   0   0   0   0   0   0   0   0   0   0   0 458   0   0   0   0   0   0
    ## [181] 564 417 409

    MaxHR :

    Se puede apreciar que hay dos valores extremos: 60 y 63. Esas frecuencias cardíacas máximas son muy bajas y por tanto lo podemos detectar como valores extraños.

    boxplot(heart$MaxHR,main="Frecuencia cardíaca máxima alcanzada")

    boxplot.stats(heart$MaxHR)$out
    ## [1] 63 60

    A continuación, sustituímos esos valores por NA y luego lo trataremos mediante Knn.

    posMaxHR <- which(heart$MaxHR==60 | heart$MaxHR==63)
    
    
    heart$MaxHR[posMaxHR] <- NA

    Se aplica kNN para ponerle un valor en función de sus vecinos más cercanos.

    library(VIM)
    ## Loading required package: colorspace
    ## Loading required package: grid
    ## VIM is ready to use.
    ## Suggestions and bug-reports can be submitted at: https://github.com/statistikat/VIM/issues
    ## 
    ## Attaching package: 'VIM'
    ## The following object is masked from 'package:datasets':
    ## 
    ##     sleep
    MaxHR_new <- kNN(heart,variable="MaxHR",dist_var =c("Age","Sex","ChestPainType","FastingBS","RestingECG","ExerciseAngina","ST_Slope","HeartDisease"),k=3)
    MaxHR_new <- MaxHR_new$MaxHR
    
    heart$MaxHR <- MaxHR_new

    Se comprueba que en esa posición hay otro valor diferente.

    heart$MaxHR[posMaxHR]
    ## [1] 144 150

    3.3 Estudio de Valores nulos

    Se aprecia que no hay ningun valor NA.

    colSums(is.na(heart))
    ##            Age            Sex  ChestPainType      RestingBP    Cholesterol 
    ##              0              0              0              0              0 
    ##      FastingBS     RestingECG          MaxHR ExerciseAngina        Oldpeak 
    ##              0              0              0              0              0 
    ##       ST_Slope   HeartDisease 
    ##              0              0

    A continuación, comprobaremos si algún campo tiene un valor 0.

    colSums(heart == 0)
    ##            Age            Sex  ChestPainType      RestingBP    Cholesterol 
    ##              0              0              0              1            172 
    ##      FastingBS     RestingECG          MaxHR ExerciseAngina        Oldpeak 
    ##            704              0              0              0            368 
    ##       ST_Slope   HeartDisease 
    ##              0            410

    Viendo esto, se puede decir que no tiene sentido que los campos RestingBP y Cholesterol tengan ceros. En este caso, podemos hablar de información perdida.

    posRestingBP <- which(heart$RestingBP == 0)
    
    posCholesterol <- which(heart$Cholesterol == 0)
    
    heart$RestingBP[posRestingBP] <- NA
    
    heart$Cholesterol[posCholesterol] <- NA

    Para esos 0, hemos metido NA ya que es un valor desconocido y ahora miraremos mediante Knn como tratar esos datos.


    Para solucionar estos valores perdidos, vamos a hacer uso de la función knn.

    RestingBP_new <- kNN(heart,variable="RestingBP",dist_var =c("Age","Sex","ChestPainType","FastingBS","RestingECG","ExerciseAngina","ST_Slope","HeartDisease"),k=3)
    RestingBP_new <- RestingBP_new$RestingBP
    
    heart$RestingBP <- RestingBP_new
    
    Cholesterol_new <- kNN(heart,variable="Cholesterol",dist_var =c("Age","Sex","ChestPainType","FastingBS","RestingECG","ExerciseAngina","ST_Slope","HeartDisease"),k=3)
    Cholesterol_new <- Cholesterol_new$Cholesterol
    
    heart$Cholesterol <- Cholesterol_new

    Se comprueba que ya no hay valores pérdidos en esas posiciones:

    heart$RestingBP[posRestingBP]
    ## [1] 135
    heart$Cholesterol[posCholesterol]
    ##   [1] 235 270 230 204 277 254 223 203 182 230 288 254 230 254 182 230 210 177
    ##  [19] 230 223 223 217 267 218 230 203 254 218 203 294 210 203 237 192 203 204
    ##  [37] 258 212 223 292 223 230 282 240 203 258 210 263 210 203 254 254 237 198
    ##  [55] 254 219 237 254 228 223 230 228 282 231 267 193 233 309 226 228 230 231
    ##  [73] 269 260 171 274 297 253 235 253 216 233 211 193 203 263 228 281 233 247
    ##  [91] 282 216 260 315 266 224 203 206 219 254 237 213 254 272 277 230 220 263
    ## [109] 203 203 204 193 237 213 263 203 256 203 254 282 218 204 254 203 219 254
    ## [127] 281 297 254 277 220 220 212 203 219 213 203 203 277 285 233 237 252 207
    ## [145] 213 309 254 203 240 297 179 233 228 302 216 235 277 283 249 241 228 213
    ## [163] 211 226 235 291 210 223 211 245 276 245

    Observamos que los valores NA fueron sustitídos por otros en función de las características de los demás atributos.
    Finalmente, vemos que ya no hay ningun valor perdido.

    colSums(is.na(heart))
    ##            Age            Sex  ChestPainType      RestingBP    Cholesterol 
    ##              0              0              0              0              0 
    ##      FastingBS     RestingECG          MaxHR ExerciseAngina        Oldpeak 
    ##              0              0              0              0              0 
    ##       ST_Slope   HeartDisease 
    ##              0              0

    3.4 Normalización

    En este apartado, lo que vamos a hacer es normalizar el campo Age usando min-max. Se creará un nuevo campo llamado Age_nor y se añadirá al dataset.

    Age_nor <- (2*(heart$Age-min(heart$Age))/(max(heart$Age)-min(heart$Age)))-1
    heart <- cbind(heart,Age_nor)

    Estos datos, están en el intervalo [-1,1]

    min(heart$Age_nor)
    ## [1] -1
    max(heart$Age_nor)
    ## [1] 1

    3.5 Discretización de variables

    En esta apartado, también usaremos la variable “Age” para discretizarla en diferentes rangos y se añadirá al dataset con el nombre Age_dis.

    Age_dist <- cut(heart$Age, breaks = c(0,40,60,80), labels = c("(0-40]","(40,60]","(60,80]"))
    
    heart <- cbind(heart,Age_dist)

    4 Análisis de los datos

    4.1 Análisis descriptivo de las variables

    Ahora, tenemos el dataset sin valores vacíos así como nuevas variables normalizadas y discretas.
    Por lo tanto, se muestra un resumen del dataset en el cual podemos ver la media, moda, cuartiles y valores mínimos y máximos en el caso de variables numéricas. En el caso de los factores, podemos ver el número de ocurrencias que tiene dicho valor.

    summary(heart)
    ##       Age        Sex     ChestPainType   RestingBP      Cholesterol 
    ##  Min.   :28.00   F:193   ASY:496       Min.   : 80.0   Min.   : 85  
    ##  1st Qu.:47.00   M:725   ATA:173       1st Qu.:120.0   1st Qu.:209  
    ##  Median :54.00           NAP:203       Median :130.0   Median :235  
    ##  Mean   :53.51           TA : 46       Mean   :132.5   Mean   :243  
    ##  3rd Qu.:60.00                         3rd Qu.:140.0   3rd Qu.:272  
    ##  Max.   :77.00                         Max.   :200.0   Max.   :603  
    ##    FastingBS       RestingECG      MaxHR     ExerciseAngina    Oldpeak       
    ##  Min.   :0.0000   LVH   :188   Min.   : 67   N:547          Min.   :-2.6000  
    ##  1st Qu.:0.0000   Normal:552   1st Qu.:120   Y:371          1st Qu.: 0.0000  
    ##  Median :0.0000   ST    :178   Median :138                  Median : 0.6000  
    ##  Mean   :0.2331                Mean   :137                  Mean   : 0.8874  
    ##  3rd Qu.:0.0000                3rd Qu.:156                  3rd Qu.: 1.5000  
    ##  Max.   :1.0000                Max.   :202                  Max.   : 6.2000  
    ##  ST_Slope    HeartDisease       Age_nor            Age_dist  
    ##  Down: 63   Min.   :0.0000   Min.   :-1.00000   (0-40] : 93  
    ##  Flat:460   1st Qu.:0.0000   1st Qu.:-0.22449   (40,60]:604  
    ##  Up  :395   Median :1.0000   Median : 0.06122   (60,80]:221  
    ##             Mean   :0.5534   Mean   : 0.04126                
    ##             3rd Qu.:1.0000   3rd Qu.: 0.30612                
    ##             Max.   :1.0000   Max.   : 1.00000

    4.2 Estudio normalidad de las variables

    4.2.1 Comprobación de la normalidad

    En este apartado, comprobaremos la normalidad de las variables numéricas, pero las que no son dicotómicas.

    Age

    qqnorm(heart$Age)
    qqline(heart$Age)

    A simple vista, se puede ver que los datos están por la recta menos por los lados y podríamos asumir normalidad. De todas formas comprobaremos esto con el test de shapiro y Lilliefors.

    shapiro.test(heart$Age)
    ## 
    ##  Shapiro-Wilk normality test
    ## 
    ## data:  heart$Age
    ## W = 0.99101, p-value = 2.165e-05
    library(nortest)
    lillie.test(heart$Age)
    ## 
    ##  Lilliefors (Kolmogorov-Smirnov) normality test
    ## 
    ## data:  heart$Age
    ## D = 0.063161, p-value = 3.158e-09

    Viendo ambos test, se puede apreciar que no sigue una distribucción normal la variable “Age”.

    RestingBP

    qqnorm(heart$RestingBP)
    qqline(heart$RestingBP)

    Tal como se aprecia, los valores no suelen estar en la recta y por lo tanto no sigue una distribucción normal.

    Cholesterol

    qqnorm(heart$Cholesterol)
    qqline(heart$Cholesterol)

    Se aprecia que bastantes puntos están muy por fuera de la recta. Con esto, concluímos que el campo Cholesterol no sigue una distribución normal.

    MaxHR

    qqnorm(heart$MaxHR)
    qqline(heart$MaxHR)

    Se observa que los puntos suelen seguir la recta, menos en algunos lados.
    Para estar más seguros aplicamos los test de shapiro y Lilliefors.

    shapiro.test(heart$MaxHR)
    ## 
    ##  Shapiro-Wilk normality test
    ## 
    ## data:  heart$MaxHR
    ## W = 0.99239, p-value = 0.0001178
    lillie.test(heart$MaxHR)
    ## 
    ##  Lilliefors (Kolmogorov-Smirnov) normality test
    ## 
    ## data:  heart$MaxHR
    ## D = 0.047706, p-value = 4.03e-05

    Según ambos test, la variable MaxHR no sigue una distribución normal.

    Oldpeak

    qqnorm(heart$Oldpeak)
    qqline(heart$Oldpeak)

    A simple vista, se observa que muchos puntos están fuera de la recta y con esto podemos decir que no sigue una distribución normal.

    Age_nor

    qqnorm(heart$Age_nor)
    qqline(heart$Age_nor)

    Se aprecia que muchos puntos siguen la recta ( similar a la variable Age sin normalizar ).
    A continuación, aplicamos los siguientes test:

    shapiro.test(heart$Age_nor)
    ## 
    ##  Shapiro-Wilk normality test
    ## 
    ## data:  heart$Age_nor
    ## W = 0.99101, p-value = 2.165e-05
    lillie.test(heart$Age_nor)
    ## 
    ##  Lilliefors (Kolmogorov-Smirnov) normality test
    ## 
    ## data:  heart$Age_nor
    ## D = 0.063161, p-value = 3.158e-09

    Nos da la misma información que la variable Age. Por tanto, podemos decir que no sigue una distribución normal.

    4.2.2 Teorema del límite central

    Dado que el tamaño de este dataset es >30, se puede decir por el teorema del límite central que las variables mencionadas anteriormente siguen una distribución normal.

    4.3 Contraste de hipótesis

    4.3.1 Queremos saber si el colesterol de las mujeres es mayor que el de los hombres

    Primero, calculamos dos variables para obtener el colesterol de hombres y mujeres.

    colHom <- heart$Cholesterol[heart$Sex=="M"]
    
    colMuj <- heart$Cholesterol[heart$Sex=="F"]

    Como hipotesis nula, se quiere saber si el colesterol en mujeres es igual que en el de los hombres.
    Como hipotesis alternativa se quiere saber si el colesterol en mujeres es mayor que en hombres.

    \[ \left\{ \begin{array}{ll} H_{0}: & \mu_M=\mu_H \\ H_{1}: & \mu_M>\mu_H \end{array} \right.\\ \ Hipótesis\ unilateral \] Por el teorema del límite central, asumimos normalidad ya que tenemos una muestra con n>30. Esto, es un contraste de hipótesis de dos muestras independientes sobre la media (varianzas desconocidas). Es un test unilateral por la derecha.

    Ahora, comprobamos la homocesdasticidad.

    var.test(colMuj, colHom)
    ## 
    ##  F test to compare two variances
    ## 
    ## data:  colMuj and colHom
    ## F = 1.3623, num df = 192, denom df = 724, p-value = 0.005232
    ## alternative hypothesis: true ratio of variances is not equal to 1
    ## 95 percent confidence interval:
    ##  1.095376 1.719717
    ## sample estimates:
    ## ratio of variances 
    ##           1.362271

    Se observa que p-value < 0.05. Por tanto, las varianzas no son iguales.

    A continuación, aplicamos el test de este contraste de hipótesis.

    t.test( colMuj,colHom , var.equal=FALSE, alternative = "greater")
    ## 
    ##  Welch Two Sample t-test
    ## 
    ## data:  colMuj and colHom
    ## t = 3.4263, df = 271.62, p-value = 0.0003533
    ## alternative hypothesis: true difference in means is greater than 0
    ## 95 percent confidence interval:
    ##  8.591104      Inf
    ## sample estimates:
    ## mean of x mean of y 
    ##  256.0933  239.5172

    Se aprecia, que p-value < 0.05. Por tanto, se rechaza la hipótesis nula y se acepta la alternativa de que las mujeres tiene más colesterol que los hombres.

    4.3.2 Azúcar en sangre es mayor en hombres que en mujeres teniendo ambos enfermedades cardíacas

    Primero, calculamos dos variables para obtener las enfermades cardíacas de hombres y mujeres.

    carHom <- heart$FastingBS[heart$Sex=="M" & heart$HeartDisease=="1"]
    
    carMuj <- heart$FastingBS[heart$Sex=="F" & heart$HeartDisease=="1"]

    Como hipotesis nula, se quiere saber si las enfermades cardíacas es igual en hombres que en mujeres.
    Como hipotesis alternativa se quiere saber si las enfermades cardíacas es mayor en hombres que en mujeres.

    \[ \left\{ \begin{array}{ll} H_{0}: & \mu_H=\mu_M \\ H_{1}: & \mu_H>\mu_M \end{array} \right.\\ \ Hipótesis\ unilateral \]

    Por el teorema del límite central, asumimos normalidad ya que tenemos una muestra con n>30. Esto, es un contraste de hipótesis de dos muestras independientes sobre la media (varianzas desconocidas). Es un test unilateral por la derecha.

    Ahora, comprobamos la homocesdasticidad.

    var.test(carHom,carMuj)
    ## 
    ##  F test to compare two variances
    ## 
    ## data:  carHom and carMuj
    ## F = 1.0073, num df = 457, denom df = 49, p-value = 0.9818
    ## alternative hypothesis: true ratio of variances is not equal to 1
    ## 95 percent confidence interval:
    ##  0.6381553 1.4800765
    ## sample estimates:
    ## ratio of variances 
    ##           1.007349

    Se observa que p-value > 0.05. Por tanto, las varianzas son iguales.

    A continuación, aplicamos el test de este contraste de hipótesis.

    t.test( carHom,carMuj , var.equal=TRUE, alternative = "greater")
    ## 
    ##  Two Sample t-test
    ## 
    ## data:  carHom and carMuj
    ## t = 0.2307, df = 506, p-value = 0.4088
    ## alternative hypothesis: true difference in means is greater than 0
    ## 95 percent confidence interval:
    ##  -0.09979074         Inf
    ## sample estimates:
    ## mean of x mean of y 
    ## 0.3362445 0.3200000

    Se aprecia, que p-value > 0.05. Por tanto, se acepta la hipótesis nula de que los hombres con enfermedad cardíaca tienen igual azucar en sangre que las mujeres con enfermedad cardíaca.

    4.4 Estudio de correlación entre las variables

    En este apartado, representaremos la matriz de correlación del dataset.
    Pasamos todsas las variables a numéricas en un dataset nuevo.

    heart_num <-heart[1:12]
    heart_num$Sex <- as.numeric(heart_num$Sex)
    heart_num$ChestPainType <- as.numeric(heart_num$ChestPainType)
    heart_num$RestingECG <- as.numeric(heart_num$RestingECG)
    heart_num$ExerciseAngina <- as.numeric(heart_num$ExerciseAngina)
    heart_num$ST_Slope <- as.numeric(heart_num$ST_Slope)


    Calculamos la correlación de las variables usando el método de pearson.

    Corelacion <- cor(heart_num,method="pearson")
    Corelacion
    ##                         Age          Sex ChestPainType    RestingBP
    ## Age             1.000000000  0.055750099   -0.07715013  0.263101716
    ## Sex             0.055750099  1.000000000   -0.12655877  0.009502133
    ## ChestPainType  -0.077150132 -0.126558765    1.00000000 -0.010820389
    ## RestingBP       0.263101716  0.009502133   -0.01082039  1.000000000
    ## Cholesterol     0.035949480 -0.122833668   -0.07645522  0.092483840
    ## FastingBS       0.198039066  0.120075988   -0.07315099  0.067728664
    ## RestingECG     -0.007484033  0.071552184   -0.07253685  0.023456877
    ## MaxHR          -0.384306668 -0.187173215    0.28583652 -0.108506017
    ## ExerciseAngina  0.215792691  0.190664102   -0.35472729  0.152883307
    ## Oldpeak         0.258611536  0.105733537   -0.17737737  0.174304136
    ## ST_Slope       -0.268263994 -0.150692544    0.21352120 -0.082226847
    ## HeartDisease    0.282038506  0.305444916   -0.38682769  0.118070714
    ##                 Cholesterol   FastingBS   RestingECG        MaxHR
    ## Age             0.035949480  0.19803907 -0.007484033 -0.384306668
    ## Sex            -0.122833668  0.12007599  0.071552184 -0.187173215
    ## ChestPainType  -0.076455221 -0.07315099 -0.072536854  0.285836516
    ## RestingBP       0.092483840  0.06772866  0.023456877 -0.108506017
    ## Cholesterol     1.000000000  0.01262851 -0.091593724 -0.005341853
    ## FastingBS       0.012628509  1.00000000  0.087049561 -0.136763624
    ## RestingECG     -0.091593724  0.08704956  1.000000000 -0.180854165
    ## MaxHR          -0.005341853 -0.13676362 -0.180854165  1.000000000
    ## ExerciseAngina  0.090879090  0.06045067  0.077500389 -0.372902545
    ## Oldpeak         0.048075140  0.05269786 -0.020437522 -0.166729389
    ## ST_Slope       -0.061766760 -0.17577434 -0.006778212  0.348051929
    ## HeartDisease    0.083198713  0.26729119  0.057384357 -0.397592228
    ##                ExerciseAngina     Oldpeak     ST_Slope HeartDisease
    ## Age                0.21579269  0.25861154 -0.268263994   0.28203851
    ## Sex                0.19066410  0.10573354 -0.150692544   0.30544492
    ## ChestPainType     -0.35472729 -0.17737737  0.213521201  -0.38682769
    ## RestingBP          0.15288331  0.17430414 -0.082226847   0.11807071
    ## Cholesterol        0.09087909  0.04807514 -0.061766760   0.08319871
    ## FastingBS          0.06045067  0.05269786 -0.175774343   0.26729119
    ## RestingECG         0.07750039 -0.02043752 -0.006778212   0.05738436
    ## MaxHR             -0.37290255 -0.16672939  0.348051929  -0.39759223
    ## ExerciseAngina     1.00000000  0.40875250 -0.428705943   0.49428199
    ## Oldpeak            0.40875250  1.00000000 -0.501921270   0.40395072
    ## ST_Slope          -0.42870594 -0.50192127  1.000000000  -0.55877071
    ## HeartDisease       0.49428199  0.40395072 -0.558770715   1.00000000

    A continuación, representamos la matriz de correlación.

    if (!require('corrplot')) install.packages('corrplot'); library('corrplot')
    ## Loading required package: corrplot
    ## corrplot 0.84 loaded
    corrplot(Corelacion, method = "number")

    A partir de aqui, podemos observar lo siguiente:
  • Las variables HeartDisease y ST_Slope tienen una correlación moderada directa (0.56).
  • Las variables Oldpeak y ST_Slope tienen una correlación moderada directa (0.50).
  • Las variables MaxHR y HeartDisease tienen una correlación débil directa (0.40).
  • 4.5 Regresión lineal

    4.5.1 Regresión lineal simple

    Se calcula un modelo de regresión lineal simple cuya variable dependiente es MaxHR y independiente es Age.

    Model_reg_sim <- lm(MaxHR~Age,data=heart)
    summary(Model_reg_sim)
    ## 
    ## Call:
    ## lm(formula = MaxHR ~ Age, data = heart)
    ## 
    ## Residuals:
    ##     Min      1Q  Median      3Q     Max 
    ## -70.879 -15.933   0.938  18.066  58.507 
    ## 
    ## Coefficients:
    ##              Estimate Std. Error t value Pr(>|t|)    
    ## (Intercept) 191.97996    4.43148   43.32   <2e-16 ***
    ## Age          -1.02754    0.08156  -12.60   <2e-16 ***
    ## ---
    ## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    ## 
    ## Residual standard error: 23.3 on 916 degrees of freedom
    ## Multiple R-squared:  0.1477, Adjusted R-squared:  0.1468 
    ## F-statistic: 158.7 on 1 and 916 DF,  p-value: < 2.2e-16

    Se observa que el coeficiente de determianción ajustado es bajo: 14.6%.

    4.5.2 Regresión lineal múltiple

    Se crea un modelo de regresión lineal múltiple con la variable dependiente MaxHR y indpendientes:HeartDisease, ST_Slope, FastingBS, Oldpeak, RestingECG, Sex, Cholesterol.

    Model_reg_mul <- lm(MaxHR~Age+HeartDisease+ST_Slope+FastingBS+Oldpeak+RestingECG+Sex+Cholesterol,data=heart)
    summary(Model_reg_mul)
    ## 
    ## Call:
    ## lm(formula = MaxHR ~ Age + HeartDisease + ST_Slope + FastingBS + 
    ##     Oldpeak + RestingECG + Sex + Cholesterol, data = heart)
    ## 
    ## Residuals:
    ##    Min     1Q Median     3Q    Max 
    ## -75.52 -13.35   0.41  15.35  57.48 
    ## 
    ## Coefficients:
    ##                    Estimate Std. Error t value Pr(>|t|)    
    ## (Intercept)      192.189947   6.728604  28.563  < 2e-16 ***
    ## Age               -0.837303   0.080857 -10.355  < 2e-16 ***
    ## HeartDisease      -9.084096   1.961702  -4.631 4.18e-06 ***
    ## ST_SlopeFlat      -1.535571   2.962891  -0.518  0.60440    
    ## ST_SlopeUp        10.238561   3.298723   3.104  0.00197 ** 
    ## FastingBS          1.342525   1.749232   0.767  0.44299    
    ## Oldpeak            1.944141   0.782412   2.485  0.01314 *  
    ## RestingECGNormal  -9.617849   1.827829  -5.262 1.78e-07 ***
    ## RestingECGST     -12.942031   2.234606  -5.792 9.60e-09 ***
    ## SexM              -4.964359   1.826623  -2.718  0.00670 ** 
    ## Cholesterol        0.004842   0.012963   0.374  0.70883    
    ## ---
    ## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    ## 
    ## Residual standard error: 21.13 on 907 degrees of freedom
    ## Multiple R-squared:  0.3057, Adjusted R-squared:  0.2981 
    ## F-statistic: 39.94 on 10 and 907 DF,  p-value: < 2.2e-16

    Se aprecia un coeficiente de determinación bajo (30%).

    4.6 Regresión logística

    4.6.1 Regresión logística simple

    Vamos a crear una regresión logística simple como variable dependiente HeartDisease y indpendiente MaxHR.

    model_logis1 <- glm(formula=HeartDisease~MaxHR,data=heart,family=binomial())
    summary(model_logis1)
    ## 
    ## Call:
    ## glm(formula = HeartDisease ~ MaxHR, family = binomial(), data = heart)
    ## 
    ## Deviance Residuals: 
    ##     Min       1Q   Median       3Q      Max  
    ## -2.3785  -1.0261   0.5797   0.9631   2.0105  
    ## 
    ## Coefficients:
    ##              Estimate Std. Error z value Pr(>|z|)    
    ## (Intercept)  5.312314   0.462283   11.49   <2e-16 ***
    ## MaxHR       -0.036878   0.003277  -11.25   <2e-16 ***
    ## ---
    ## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    ## 
    ## (Dispersion parameter for binomial family taken to be 1)
    ## 
    ##     Null deviance: 1262.1  on 917  degrees of freedom
    ## Residual deviance: 1105.8  on 916  degrees of freedom
    ## AIC: 1109.8
    ## 
    ## Number of Fisher Scoring iterations: 4

    Calculamos la bondad de ajuste usando el test de hoslem.

    if (!require('ResourceSelection')) install.packages('ResourceSelection'); library('ResourceSelection')
    ## Loading required package: ResourceSelection
    ## ResourceSelection 0.3-5   2019-07-22
    hoslem.test(heart$HeartDisease,fitted(model_logis1))
    ## 
    ##  Hosmer and Lemeshow goodness of fit (GOF) test
    ## 
    ## data:  heart$HeartDisease, fitted(model_logis1)
    ## X-squared = 15.098, df = 8, p-value = 0.05726

    Se observa que p-value >0.05. Por tanto, el modelo ajusta bien los datos.

    4.6.2 Regresión logística múltiple

    Calculamos una regresión logística múltiple con HeartDisease como variable dependiente y ST_Slope, Oldpeak, MaxHR, ChestPainType, RestingBP, Age_nor como variables dependientes

    model_logis2 <- glm(formula=HeartDisease~ST_Slope+Oldpeak+MaxHR+ChestPainType+RestingBP+Age_nor,data=heart,family=binomial())
    summary(model_logis2)
    ## 
    ## Call:
    ## glm(formula = HeartDisease ~ ST_Slope + Oldpeak + MaxHR + ChestPainType + 
    ##     RestingBP + Age_nor, family = binomial(), data = heart)
    ## 
    ## Deviance Residuals: 
    ##     Min       1Q   Median       3Q      Max  
    ## -2.6439  -0.4265   0.2657   0.4951   2.5609  
    ## 
    ## Coefficients:
    ##                   Estimate Std. Error z value Pr(>|z|)    
    ## (Intercept)       2.310735   0.987247   2.341 0.019254 *  
    ## ST_SlopeFlat      0.900785   0.396679   2.271 0.023158 *  
    ## ST_SlopeUp       -1.417499   0.413301  -3.430 0.000604 ***
    ## Oldpeak           0.422374   0.108012   3.910 9.21e-05 ***
    ## MaxHR            -0.013499   0.004404  -3.065 0.002175 ** 
    ## ChestPainTypeATA -2.288611   0.296705  -7.713 1.22e-14 ***
    ## ChestPainTypeNAP -1.778255   0.233869  -7.604 2.88e-14 ***
    ## ChestPainTypeTA  -1.593164   0.393194  -4.052 5.08e-05 ***
    ## RestingBP         0.003921   0.005694   0.689 0.490997    
    ## Age_nor           0.556923   0.290248   1.919 0.055012 .  
    ## ---
    ## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    ## 
    ## (Dispersion parameter for binomial family taken to be 1)
    ## 
    ##     Null deviance: 1262.14  on 917  degrees of freedom
    ## Residual deviance:  695.39  on 908  degrees of freedom
    ## AIC: 715.39
    ## 
    ## Number of Fisher Scoring iterations: 5

    Se aprecia que el AIC es mucho menor y por tanto, el modelo es mejor.
    Calculamos la bondad de ajuste:

    hoslem.test(heart$HeartDisease,fitted(model_logis2))
    ## 
    ##  Hosmer and Lemeshow goodness of fit (GOF) test
    ## 
    ## data:  heart$HeartDisease, fitted(model_logis2)
    ## X-squared = 12.797, df = 8, p-value = 0.119

    Se aprecia que el modelo tiene p-value > 0.05. Por tanto, ajusta bien los datos.

    4.7 Modelos de clasificación

    head(heart)
    ##   Age Sex ChestPainType RestingBP Cholesterol FastingBS RestingECG MaxHR
    ## 1  40   M           ATA       140         289         0     Normal   172
    ## 2  49   F           NAP       160         180         0     Normal   156
    ## 3  37   M           ATA       130         283         0         ST    98
    ## 4  48   F           ASY       138         214         0     Normal   108
    ## 5  54   M           NAP       150         195         0     Normal   122
    ## 6  39   M           NAP       120         339         0     Normal   170
    ##   ExerciseAngina Oldpeak ST_Slope HeartDisease     Age_nor Age_dist
    ## 1              N     0.0       Up            0 -0.51020408   (0-40]
    ## 2              N     1.0     Flat            1 -0.14285714  (40,60]
    ## 3              N     0.0       Up            0 -0.63265306   (0-40]
    ## 4              Y     1.5     Flat            1 -0.18367347  (40,60]
    ## 5              N     0.0       Up            0  0.06122449  (40,60]
    ## 6              N     0.0       Up            0 -0.55102041   (0-40]

    4.7.1 Preparación de los datos para el modelo

    Nos interesa desordenar los datos para poder elegir registros aleatorios. Guardaremos los datos con el nuevo nombre de: heart_clasification

    set.seed(1)
    heart_clasification <- heart[sample(nrow(heart)),]

    Para la futura evaluación del árbol de decisión, es necesario dividir el conjunto de datos en un conjunto de entrenamiento y un conjunto de prueba. El conjunto de entrenamiento es el subconjunto del conjunto original de datos utilizado para construir un primer modelo; y el conjunto de prueba, el subconjunto del conjunto original de datos utilizado para evaluar la calidad del modelo.

    Lo más correcto será utilizar un conjunto de datos diferente del que utilizamos para construir el árbol, es decir, un conjunto diferente del de entrenamiento. No hay ninguna proporción fijada con respecto al número relativo de componentes de cada subconjunto, pero la más utilizada acostumbra a ser 2/3 para el conjunto de entrenamiento y 1/3, para el conjunto de prueba.

    La variable por la que clasificaremos es HeartDisease, para clasificar si existe riesgo de enfermedad cardíaca o no, y que se sitúa en nuestro en la columna, la 16. De esta forma, tendremos un conjunto de datos para el entrenamiento y uno para la validación

    set.seed(666)
    y <- heart_clasification[,12] 
    X <- heart_clasification[,1:11] 

    Dividimos el dataset en dos partes diferenciadas, train y test. Podemos crear directamente un rango utilizando el parámetro split_prop

    split_prop <- 3 
    indexes = sample(1:nrow( heart_clasification), size=floor(((split_prop-1)/split_prop)*nrow(heart_clasification)))
    trainx<-X[indexes,]
    trainy<-y[indexes]
    testx<-X[-indexes,]
    testy<-y[-indexes]

    4.7.2 Creación del modelo, calidad del modelo y extracción de reglas

    if(!require(ggplot2)){
        install.packages('ggplot2', repos='http://cran.us.r-project.org')
        library(ggplot2)
    }
    ## Loading required package: ggplot2
    if(!require(ggpubr)){
        install.packages('ggpubr', repos='http://cran.us.r-project.org')
        library(ggpubr)
    }
    ## Loading required package: ggpubr
    if(!require(grid)){
        install.packages('grid', repos='http://cran.us.r-project.org')
        library(grid)
    }
    
    if(!require(gridExtra)){
        install.packages('gridExtra', repos='http://cran.us.r-project.org')
        library(gridExtra)
    }
    ## Loading required package: gridExtra
    if(!require(C50)){
        install.packages('C50', repos='http://cran.us.r-project.org')
        library(C50)
    }
    ## Loading required package: C50
    library("rpart")       
    library("rpart.plot")  

    Se crea el árbol de decisión usando los datos de entrenamiento:

    Utilizaremos dos bibliotecas diferentes, una de ellas es rpart, para crear el árbol de decisión y rpart.plot para representar visualmente nuestro árbol de decisión.

    modelo_clasificacion_rpart <- rpart(formula = trainy ~ ., data = trainx, method = "class" )
    summary(modelo_clasificacion_rpart)
    ## Call:
    ## rpart(formula = trainy ~ ., data = trainx, method = "class")
    ##   n= 612 
    ## 
    ##           CP nsplit rel error    xerror       xstd
    ## 1 0.61433447      0 1.0000000 1.0000000 0.04217798
    ## 2 0.02559727      1 0.3856655 0.3856655 0.03276017
    ## 3 0.02389078      3 0.3344710 0.4061433 0.03341593
    ## 4 0.01365188      5 0.2866894 0.3412969 0.03121703
    ## 5 0.01000000      7 0.2593857 0.3276451 0.03070557
    ## 
    ## Variable importance
    ##       ST_Slope        Oldpeak  ChestPainType ExerciseAngina          MaxHR 
    ##             30             18             16             13             13 
    ##            Age            Sex    Cholesterol      RestingBP 
    ##              6              2              1              1 
    ## 
    ## Node number 1: 612 observations,    complexity param=0.6143345
    ##   predicted class=1  expected loss=0.4787582  P(node) =1
    ##     class counts:   293   319
    ##    probabilities: 0.479 0.521 
    ##   left son=2 (272 obs) right son=3 (340 obs)
    ##   Primary splits:
    ##       ST_Slope       splits as  RRL,       improve=121.41240, (0 missing)
    ##       ChestPainType  splits as  RLLL,      improve= 90.58827, (0 missing)
    ##       ExerciseAngina splits as  LR,        improve= 80.19091, (0 missing)
    ##       Oldpeak        < 0.45  to the left,  improve= 53.26917, (0 missing)
    ##       MaxHR          < 150.5 to the right, improve= 47.53931, (0 missing)
    ##   Surrogate splits:
    ##       Oldpeak        < 0.35  to the left,  agree=0.775, adj=0.493, (0 split)
    ##       ExerciseAngina splits as  LR,        agree=0.717, adj=0.364, (0 split)
    ##       ChestPainType  splits as  RLLL,      agree=0.699, adj=0.324, (0 split)
    ##       MaxHR          < 152.5 to the right, agree=0.686, adj=0.294, (0 split)
    ##       Age            < 54.5  to the left,  agree=0.629, adj=0.165, (0 split)
    ## 
    ## Node number 2: 272 observations,    complexity param=0.02559727
    ##   predicted class=0  expected loss=0.1691176  P(node) =0.4444444
    ##     class counts:   226    46
    ##    probabilities: 0.831 0.169 
    ##   left son=4 (185 obs) right son=5 (87 obs)
    ##   Primary splits:
    ##       ChestPainType  splits as  RLLL,      improve=16.788120, (0 missing)
    ##       Oldpeak        < 0.45  to the left,  improve=11.881400, (0 missing)
    ##       ExerciseAngina splits as  LR,        improve= 9.085244, (0 missing)
    ##       FastingBS      < 0.5   to the left,  improve= 6.480573, (0 missing)
    ##       Age            < 55.5  to the left,  improve= 5.507843, (0 missing)
    ##   Surrogate splits:
    ##       ExerciseAngina splits as  LR,        agree=0.739, adj=0.184, (0 split)
    ##       MaxHR          < 112.5 to the right, agree=0.695, adj=0.046, (0 split)
    ##       Oldpeak        < 0.85  to the left,  agree=0.691, adj=0.034, (0 split)
    ##       Cholesterol    < 348   to the left,  agree=0.688, adj=0.023, (0 split)
    ## 
    ## Node number 3: 340 observations,    complexity param=0.02389078
    ##   predicted class=1  expected loss=0.1970588  P(node) =0.5555556
    ##     class counts:    67   273
    ##    probabilities: 0.197 0.803 
    ##   left son=6 (58 obs) right son=7 (282 obs)
    ##   Primary splits:
    ##       MaxHR          < 150.5 to the right, improve=15.923540, (0 missing)
    ##       ChestPainType  splits as  RLLL,      improve=15.109280, (0 missing)
    ##       Sex            splits as  LR,        improve=13.255020, (0 missing)
    ##       ExerciseAngina splits as  LR,        improve= 9.783180, (0 missing)
    ##       RestingBP      < 130.5 to the left,  improve= 4.033701, (0 missing)
    ## 
    ## Node number 4: 185 observations
    ##   predicted class=0  expected loss=0.04864865  P(node) =0.3022876
    ##     class counts:   176     9
    ##    probabilities: 0.951 0.049 
    ## 
    ## Node number 5: 87 observations,    complexity param=0.02559727
    ##   predicted class=0  expected loss=0.4252874  P(node) =0.1421569
    ##     class counts:    50    37
    ##    probabilities: 0.575 0.425 
    ##   left son=10 (58 obs) right son=11 (29 obs)
    ##   Primary splits:
    ##       Oldpeak        < 0.45  to the left,  improve=9.666667, (0 missing)
    ##       FastingBS      < 0.5   to the left,  improve=6.448240, (0 missing)
    ##       ExerciseAngina splits as  LR,        improve=5.287878, (0 missing)
    ##       RestingBP      < 127   to the right, improve=3.823607, (0 missing)
    ##       Age            < 57.5  to the left,  improve=3.321839, (0 missing)
    ##   Surrogate splits:
    ##       Age            < 60.5  to the left,  agree=0.724, adj=0.172, (0 split)
    ##       FastingBS      < 0.5   to the left,  agree=0.701, adj=0.103, (0 split)
    ##       ExerciseAngina splits as  LR,        agree=0.690, adj=0.069, (0 split)
    ## 
    ## Node number 6: 58 observations,    complexity param=0.02389078
    ##   predicted class=0  expected loss=0.4655172  P(node) =0.09477124
    ##     class counts:    31    27
    ##    probabilities: 0.534 0.466 
    ##   left son=12 (28 obs) right son=13 (30 obs)
    ##   Primary splits:
    ##       ChestPainType splits as  RLLR,      improve=5.028736, (0 missing)
    ##       Cholesterol   < 252   to the left,  improve=4.087875, (0 missing)
    ##       Oldpeak       < 0.3   to the right, improve=2.702825, (0 missing)
    ##       FastingBS     < 0.5   to the left,  improve=2.177545, (0 missing)
    ##       RestingECG    splits as  LRR,       improve=1.980081, (0 missing)
    ##   Surrogate splits:
    ##       Cholesterol < 252   to the left,  agree=0.741, adj=0.464, (0 split)
    ##       RestingBP   < 136.5 to the left,  agree=0.638, adj=0.250, (0 split)
    ##       Oldpeak     < 0.75  to the right, agree=0.638, adj=0.250, (0 split)
    ##       Age         < 58.5  to the left,  agree=0.603, adj=0.179, (0 split)
    ##       Sex         splits as  LR,        agree=0.603, adj=0.179, (0 split)
    ## 
    ## Node number 7: 282 observations,    complexity param=0.01365188
    ##   predicted class=1  expected loss=0.1276596  P(node) =0.4607843
    ##     class counts:    36   246
    ##    probabilities: 0.128 0.872 
    ##   left son=14 (36 obs) right son=15 (246 obs)
    ##   Primary splits:
    ##       Sex            splits as  LR,        improve=8.282765, (0 missing)
    ##       ExerciseAngina splits as  LR,        improve=3.716003, (0 missing)
    ##       ChestPainType  splits as  RLLL,      improve=3.550889, (0 missing)
    ##       Oldpeak        < 0.15  to the right, improve=2.227013, (0 missing)
    ##       RestingBP      < 132.5 to the left,  improve=1.994501, (0 missing)
    ## 
    ## Node number 10: 58 observations
    ##   predicted class=0  expected loss=0.2586207  P(node) =0.09477124
    ##     class counts:    43    15
    ##    probabilities: 0.741 0.259 
    ## 
    ## Node number 11: 29 observations
    ##   predicted class=1  expected loss=0.2413793  P(node) =0.04738562
    ##     class counts:     7    22
    ##    probabilities: 0.241 0.759 
    ## 
    ## Node number 12: 28 observations
    ##   predicted class=0  expected loss=0.25  P(node) =0.04575163
    ##     class counts:    21     7
    ##    probabilities: 0.750 0.250 
    ## 
    ## Node number 13: 30 observations
    ##   predicted class=1  expected loss=0.3333333  P(node) =0.04901961
    ##     class counts:    10    20
    ##    probabilities: 0.333 0.667 
    ## 
    ## Node number 14: 36 observations,    complexity param=0.01365188
    ##   predicted class=1  expected loss=0.4444444  P(node) =0.05882353
    ##     class counts:    16    20
    ##    probabilities: 0.444 0.556 
    ##   left son=28 (16 obs) right son=29 (20 obs)
    ##   Primary splits:
    ##       ExerciseAngina splits as  LR,        improve=5.377778, (0 missing)
    ##       Oldpeak        < 0.25  to the right, improve=3.432950, (0 missing)
    ##       RestingBP      < 134   to the left,  improve=2.818025, (0 missing)
    ##       ChestPainType  splits as  RLLR,      improve=1.808547, (0 missing)
    ##       MaxHR          < 133.5 to the left,  improve=1.455796, (0 missing)
    ##   Surrogate splits:
    ##       ChestPainType splits as  RLLL,      agree=0.722, adj=0.375, (0 split)
    ##       Cholesterol   < 273.5 to the left,  agree=0.694, adj=0.312, (0 split)
    ##       Age           < 61.5  to the right, agree=0.667, adj=0.250, (0 split)
    ##       RestingECG    splits as  LRR,       agree=0.667, adj=0.250, (0 split)
    ##       RestingBP     < 122   to the left,  agree=0.639, adj=0.187, (0 split)
    ## 
    ## Node number 15: 246 observations
    ##   predicted class=1  expected loss=0.08130081  P(node) =0.4019608
    ##     class counts:    20   226
    ##    probabilities: 0.081 0.919 
    ## 
    ## Node number 28: 16 observations
    ##   predicted class=0  expected loss=0.25  P(node) =0.02614379
    ##     class counts:    12     4
    ##    probabilities: 0.750 0.250 
    ## 
    ## Node number 29: 20 observations
    ##   predicted class=1  expected loss=0.2  P(node) =0.03267974
    ##     class counts:     4    16
    ##    probabilities: 0.200 0.800

    Vamos a representar gráficamente el arbol obtenido de dos maneras diferentes:

    rpart.plot(modelo_clasificacion_rpart, type=2,extra = 2, under = TRUE, faclen=5,cex=.55) 

    rpart.plot(modelo_clasificacion_rpart, type=2,extra = 8, under = TRUE, faclen=5,cex=.55) 

    En el primer árbol Observamos las tasas de clasificación para cada nodo, expresada como el número de clasificaciones correctas y el número de observaciones en el nodo. En el segundo gráfico observamos la probabilidad por cada clase.

    4.7.3 Predición del modelo

    predicted_model <- predict( modelo_clasificacion_rpart, testx, type="class" )
    print(sprintf("La precisión del modelo4 es: %.4f %%",100*sum(predicted_model == testy) / length(predicted_model)))
    ## [1] "La precisión del modelo4 es: 83.6601 %"

    Vamos a crear la matriz de confusión

    mat_conf<-table(testy,Predicted=predicted_model)
    mat_conf
    ##      Predicted
    ## testy   0   1
    ##     0  98  19
    ##     1  31 158
    if(!require(gmodels)){
        install.packages('gmodels', repos='http://cran.us.r-project.org')
        library(gmodels)
    }
    ## Loading required package: gmodels
    CrossTable(testy, predicted_model,prop.chisq  = FALSE, prop.c = FALSE, prop.r =FALSE,dnn = c('Reality', 'Prediction'))
    ## 
    ##  
    ##    Cell Contents
    ## |-------------------------|
    ## |                       N |
    ## |         N / Table Total |
    ## |-------------------------|
    ## 
    ##  
    ## Total Observations in Table:  306 
    ## 
    ##  
    ##              | Prediction 
    ##      Reality |         0 |         1 | Row Total | 
    ## -------------|-----------|-----------|-----------|
    ##            0 |        98 |        19 |       117 | 
    ##              |     0.320 |     0.062 |           | 
    ## -------------|-----------|-----------|-----------|
    ##            1 |        31 |       158 |       189 | 
    ##              |     0.101 |     0.516 |           | 
    ## -------------|-----------|-----------|-----------|
    ## Column Total |       129 |       177 |       306 | 
    ## -------------|-----------|-----------|-----------|
    ## 
    ## 

    añadir: DISCRETIZAR MÁS VARIABLES, ORDENAR VARIABLES SEGÚN EL ANÁLISIS PCA, REALIZAR BOOSTING, OBTENER REGLAS DEL MODELO C50

    if(!require(C50)){
        install.packages('C50', repos='http://cran.us.r-project.org')
        library(C50)
    }
    trainy = as.factor(trainy)
    modelo_clasificacion_C50 <- C50::C5.0(trainx, trainy,rules=TRUE,control = C5.0Control(noGlobalPruning = FALSE) )
    summary(modelo_clasificacion_C50)
    ## 
    ## Call:
    ## C5.0.default(x = trainx, y = trainy, rules = TRUE, control
    ##  = C5.0Control(noGlobalPruning = FALSE))
    ## 
    ## 
    ## C5.0 [Release 2.07 GPL Edition]      Mon Dec 13 19:37:07 2021
    ## -------------------------------
    ## 
    ## Class specified by attribute `outcome'
    ## 
    ## Read 612 cases (12 attributes) from undefined.data
    ## 
    ## Rules:
    ## 
    ## Rule 1: (77/1, lift 2.0)
    ##  Sex = F
    ##  RestingBP <= 148
    ##  FastingBS <= 0
    ##  ExerciseAngina = N
    ##  ->  class 0  [0.975]
    ## 
    ## Rule 2: (40/3, lift 1.9)
    ##  ChestPainType = NAP
    ##  RestingBP <= 132
    ##  MaxHR > 150
    ##  ->  class 0  [0.905]
    ## 
    ## Rule 3: (72/8, lift 1.8)
    ##  ChestPainType in {ATA, TA}
    ##  MaxHR > 150
    ##  ->  class 0  [0.878]
    ## 
    ## Rule 4: (272/46, lift 1.7)
    ##  ST_Slope = Up
    ##  ->  class 0  [0.828]
    ## 
    ## Rule 5: (50, lift 1.9)
    ##  ChestPainType = ASY
    ##  RestingBP <= 131
    ##  FastingBS > 0
    ##  ->  class 1  [0.981]
    ## 
    ## Rule 6: (23, lift 1.8)
    ##  ChestPainType = ASY
    ##  Cholesterol <= 197
    ##  ExerciseAngina = Y
    ##  ->  class 1  [0.960]
    ## 
    ## Rule 7: (60/2, lift 1.8)
    ##  ChestPainType = ASY
    ##  FastingBS > 0
    ##  Oldpeak > 0.6
    ##  ->  class 1  [0.952]
    ## 
    ## Rule 8: (75/3, lift 1.8)
    ##  Sex = M
    ##  ChestPainType = ASY
    ##  Cholesterol > 227
    ##  FastingBS <= 0
    ##  ExerciseAngina = Y
    ##  ->  class 1  [0.948]
    ## 
    ## Rule 9: (64/3, lift 1.8)
    ##  Sex = M
    ##  Oldpeak <= 0.3
    ##  ST_Slope in {Down, Flat}
    ##  ->  class 1  [0.939]
    ## 
    ## Rule 10: (9, lift 1.7)
    ##  Sex = M
    ##  ChestPainType = ASY
    ##  RestingBP <= 126
    ##  MaxHR > 146
    ##  MaxHR <= 160
    ##  ST_Slope = Up
    ##  ->  class 1  [0.909]
    ## 
    ## Rule 11: (8, lift 1.7)
    ##  ChestPainType = ASY
    ##  RestingBP <= 126
    ##  ExerciseAngina = N
    ##  Oldpeak > 0.4
    ##  ST_Slope = Up
    ##  ->  class 1  [0.900]
    ## 
    ## Rule 12: (340/67, lift 1.5)
    ##  ST_Slope in {Down, Flat}
    ##  ->  class 1  [0.801]
    ## 
    ## Default class: 1
    ## 
    ## 
    ## Evaluation on training data (612 cases):
    ## 
    ##          Rules     
    ##    ----------------
    ##      No      Errors
    ## 
    ##      12   49( 8.0%)   <<
    ## 
    ## 
    ##     (a)   (b)    <-classified as
    ##    ----  ----
    ##     260    33    (a): class 0
    ##      16   303    (b): class 1
    ## 
    ## 
    ##  Attribute usage:
    ## 
    ##  100.00% ST_Slope
    ##   48.69% ChestPainType
    ##   38.24% FastingBS
    ##   35.62% Sex
    ##   29.90% ExerciseAngina
    ##   27.12% RestingBP
    ##   21.24% Oldpeak
    ##   19.77% MaxHR
    ##   16.01% Cholesterol
    ## 
    ## 
    ## Time: 0.0 secs

    Explicar reglas:

    predicted_model <- predict( modelo_clasificacion_C50, testx, type="class" )
    print(sprintf("La precisión del modelo es: %.4f %%",100*sum(predicted_model == testy) / length(predicted_model)))
    ## [1] "La precisión del modelo es: 85.2941 %"

    5 Visualización

    Vamos a realizar diferentes estudios gráficos para analizar las distintas variables del modelo y las relaciones entre ellas.

    Para ello, diferenciaremos entre los tipos de variables continuas y discretas para su análisis y sí fuera necesario transformaremos las variables para su estudio más eficiente.

    head(heart)
    ##   Age Sex ChestPainType RestingBP Cholesterol FastingBS RestingECG MaxHR
    ## 1  40   M           ATA       140         289         0     Normal   172
    ## 2  49   F           NAP       160         180         0     Normal   156
    ## 3  37   M           ATA       130         283         0         ST    98
    ## 4  48   F           ASY       138         214         0     Normal   108
    ## 5  54   M           NAP       150         195         0     Normal   122
    ## 6  39   M           NAP       120         339         0     Normal   170
    ##   ExerciseAngina Oldpeak ST_Slope HeartDisease     Age_nor Age_dist
    ## 1              N     0.0       Up            0 -0.51020408   (0-40]
    ## 2              N     1.0     Flat            1 -0.14285714  (40,60]
    ## 3              N     0.0       Up            0 -0.63265306   (0-40]
    ## 4              Y     1.5     Flat            1 -0.18367347  (40,60]
    ## 5              N     0.0       Up            0  0.06122449  (40,60]
    ## 6              N     0.0       Up            0 -0.55102041   (0-40]

    Variables discretas:

    library(ggplot2)
    ggplot(data=heart,aes(x=Age_dist,fill=(factor(HeartDisease))))+geom_bar() + ggtitle("Enfermedad Cardiaca por grupo de edad(G1)") + labs(x="Edad", colour= "HeartDisease") 

    ggplot(data=heart,aes(x=Sex,fill=factor(HeartDisease)))+geom_bar() + ggtitle("Enfermedad Cardiaca por sexo(G2)") + labs(x="sexo", colour= "HeartDisease") 

    ggplot(data=heart,aes(x=ChestPainType,fill=factor(HeartDisease)))+geom_bar() + ggtitle("Enfermedad Cardiaca por ChestPainType(G3)") + labs(x="ChestPainType", colour= "HeartDisease") 

    ggplot(data=heart,aes(x=RestingECG,fill=factor(HeartDisease)))+geom_bar() + ggtitle("Enfermedad Cardiaca por RestingECG(G4)") + labs(x="RestingECG", colour= "HeartDisease") 

    # ExerciseAngina & HeartDisease
    ggplot(data=heart,aes(x=ExerciseAngina,fill=factor(HeartDisease)))+geom_bar() + ggtitle("Enfermedad Cardiaca por ExerciseAngina(G5)") + labs(x="ExerciseAngina", colour= "HeartDisease") 

    # ST_Slope & HeartDisease
    ggplot(data=heart,aes(x=ST_Slope,fill=factor(HeartDisease)))+geom_bar() + ggtitle("Enfermedad Cardiaca por ST_Slope(G6)") + labs(x="ST_Slope", colour= "HeartDisease") 

    # FastingBS & HeartDisease
    ggplot(data=heart,aes(x=FastingBS,fill=factor(HeartDisease)))+geom_bar() + ggtitle("Enfermedad Cardiaca por FastingBS(G7)") + labs(x="FastingBS", colour= "HeartDisease") 

    Variables continuas:

    EStudiamos la relación entre la variable edad y colesterol, ya que hemos estudiado su relación anteriormente.

    # Coresterol & Sexo
    ggplot(heart, aes(x =heart$Age, y = heart$Cholesterol)) + geom_point()+
      geom_smooth(method = "loess") 
    ## Warning: Use of `heart$Age` is discouraged. Use `Age` instead.
    ## Warning: Use of `heart$Cholesterol` is discouraged. Use `Cholesterol` instead.
    ## Warning: Use of `heart$Age` is discouraged. Use `Age` instead.
    ## Warning: Use of `heart$Cholesterol` is discouraged. Use `Cholesterol` instead.
    ## `geom_smooth()` using formula 'y ~ x'

    Estudiamos el resto de variables continuas, en relación con su edad y el riesgo o no de sufrir una enfermedad cardíaca:

    ggplot(heart, aes(RestingBP, Age, colour = HeartDisease)) + 
      geom_point()+ ggtitle("AÑADIR TITULO GRÁFICO") 

    ggplot(heart, aes(Cholesterol, Age, colour = HeartDisease)) + 
      geom_point()+ ggtitle("AÑADIR TITULO GRÁFICO") 

    ggplot(heart, aes(MaxHR, Age, colour = HeartDisease)) + 
      geom_point() + ggtitle("AÑADIR TITULO GRÁFICO") 

    ggplot(heart, aes(Oldpeak, Age, colour = HeartDisease)) + 
      geom_point() + ggtitle("AÑADIR TITULO GRÁFICO") 

    COMENTAR CONCLUSIONES DE CADA GRÁFICO y añadir más gráficos si fuera necesario

    6 Conclusiones

    añadir # Recursos

    añadir